refactor: 统一金蝶BFI配置为BfiProperties类注入并补齐Nacos配置缺项

1. BfiProperties 新增 payResult/receivedInvoiceResult/receiptClaimPush/invoiceReceipt/customer/blacklist/invoiceResult/arResult/billLock/autoSync 嵌套配置类,收口 thirdParty.bfi.* 全部键;receivedInvoice 补 queryWindowDays/resultWindowDays/lockLeaseSeconds
2. 6 个定时任务、审批监听器及 6 个 ServiceImpl 共 13 处 @Value 改为 BfiProperties 注入(Nacos 刷新后自动重绑定,无需重启)
3. 本地 third-party-api.yaml 补 invoiceReceipt.invoiceTypes/compensateLimit 与 autoSync 整段,Nacos blade-dev.yaml 补 invoiceReceipt.lockLeaseSeconds
This commit is contained in:
刘泉佳
2026-10-14 11:10:20 +08:00
parent 805ca9d380
commit 5470eaf9c5
15 changed files with 298 additions and 151 deletions
@@ -73,6 +73,56 @@ public class BfiProperties {
*/
private ClaimAnnounce claimAnnounce = new ClaimAnnounce();
/**
* 付款结果定时回写配置(A103-2/A103-4,总开关同时控制应收勾稽、开票结果回写)
*/
private PayResult payResult = new PayResult();
/**
* 收票单结果定时回写开关(A801-3)
*/
private ReceivedInvoiceResult receivedInvoiceResult = new ReceivedInvoiceResult();
/**
* 收款认领推送配置(A301-3)
*/
private ReceiptClaimPush receiptClaimPush = new ReceiptClaimPush();
/**
* 全票池发票定时同步配置(A801-1)
*/
private InvoiceReceipt invoiceReceipt = new InvoiceReceipt();
/**
* 客商金蝶数据定时同步配置(A902-1/A902-2)
*/
private Customer customer = new Customer();
/**
* 金蝶黑名单查询配置
*/
private Blacklist blacklist = new Blacklist();
/**
* 开票结果回写锁配置(A303-5)
*/
private InvoiceResult invoiceResult = new InvoiceResult();
/**
* 应收单勾稽回写锁配置(A302-4)
*/
private ArResult arResult = new ArResult();
/**
* 金蝶单据锁定补偿配置
*/
private BillLock billLock = new BillLock();
/**
* 审批通过自动同步金蝶配置(结算单/付款申请/开票申请/收票登记)
*/
private AutoSync autoSync = new AutoSync();
/**
* 应付/应收/收票单分录物料映射配置(A102-2/A302-2/A303-2 共用):
* 运输类按项目业务模式映射——国内运输按运单运输方式映射、国际运输映射国际货代服务;
@@ -127,6 +177,21 @@ public class BfiProperties {
* 真实物料口径与金蝶对齐后替换(与应收/应付联调临时值同源)
*/
private String materialNumber = "SP0324";
/**
* A801-3 推送幂等预检回看窗口天数(金蝶修改时间窗口,契约约束不超过 1 个月)
*/
private int queryWindowDays = 30;
/**
* A801-3 定时回写轮询窗口天数(同样受金蝶 1 个月窗口约束)
*/
private int resultWindowDays = 30;
/**
* A801-3 回写 single-flight 锁租约秒数,须大于最坏一轮耗时(批量远程查询 + 逐单回写)
*/
private long lockLeaseSeconds = 1800;
}
/**
@@ -175,4 +240,174 @@ public class BfiProperties {
private String loading = "XDWL11002004";
}
/**
* 付款结果回写配置项(A103-2/A103-4)
*/
@Data
public static class PayResult {
/**
* 回写任务开关,代码默认关闭(安全兜底),由 Nacos 按环境显式开启
*/
private boolean syncEnabled = false;
/**
* 回写 single-flight 锁租约秒数,须大于最坏一轮耗时(分批远程查询 + 逐单回写)
*/
private long lockLeaseSeconds = 1800;
}
/**
* 收票单结果回写配置项(A801-3)
*/
@Data
public static class ReceivedInvoiceResult {
/**
* 回写任务开关,默认关闭(联调稳定后开启)
*/
private boolean syncEnabled = false;
}
/**
* 收款认领推送配置项(A301-3)
*/
@Data
public static class ReceiptClaimPush {
/**
* 推送任务开关,默认关闭(联调稳定后开启)
*/
private boolean syncEnabled = false;
/**
* 推送 single-flight 锁租约秒数,须大于最坏一轮耗时(逐认领人远程查公告 + 逐条推送)
*/
private long lockLeaseSeconds = 1800;
}
/**
* 全票池发票同步配置项(A801-1)
*/
@Data
public static class InvoiceReceipt {
/**
* 同步任务开关,默认关闭(上线先手动跑一次全窗口铺底)
*/
private boolean syncEnabled = false;
/**
* 增量窗口天数(按票池更新时间滚动)
*/
private int incrementDays = 30;
/**
* 同步发票种类白名单(逗号分隔票易通编码,如 26,27 数电普票/专票),为空不限制
*/
private String invoiceTypes = "";
/**
* 同步 single-flight 锁租约秒数,须大于最坏一轮耗时;进程异常退出时锁在租约到期后自动释放
*/
private long lockLeaseSeconds = 1800;
}
/**
* 客商金蝶数据同步配置项(A902-1/A902-2)
*/
@Data
public static class Customer {
/**
* 同步任务开关,默认关闭
*/
private boolean syncEnabled = false;
/**
* 同步 single-flight 锁租约秒数,须大于最坏一轮耗时(复查 + 批量推送 + 停用联动)
*/
private long lockLeaseSeconds = 1800;
}
/**
* 金蝶黑名单查询配置项
*/
@Data
public static class Blacklist {
/**
* 客商提审命中风险警示类(B)时是否一并拦截;默认 false 仅放行告警,禁止交易类(A)始终拦截
*/
private boolean blockRiskWarning = false;
}
/**
* 开票结果回写锁配置项(A303-5)
*/
@Data
public static class InvoiceResult {
/**
* 回写 single-flight 锁租约秒数
*/
private long lockLeaseSeconds = 1800;
}
/**
* 应收单勾稽回写锁配置项(A302-4)
*/
@Data
public static class ArResult {
/**
* 勾稽 single-flight 锁租约秒数
*/
private long lockLeaseSeconds = 1800;
}
/**
* 金蝶单据锁定补偿配置项
*/
@Data
public static class BillLock {
/**
* 锁定补偿开关,默认关闭(安全兜底)
*/
private boolean retryEnabled = false;
}
/**
* 审批通过自动同步金蝶配置项(结算单 A102-2/A302-2、付款申请 A103-1/A103-3、开票申请 A303-1、收票 A303-2+A302-6)
*/
@Data
public static class AutoSync {
/**
* 结算单审批后自动推送开关
*/
private boolean settlement = false;
/**
* 付款申请审批后自动推送开关
*/
private boolean payment = false;
/**
* 开票申请审批后自动推送开关
*/
private boolean invoiceApply = false;
/**
* 收票登记审批后自动推送开关
*/
private boolean receipt = false;
/**
* failed 单据定时重推开关(仅重推生成失败,不扫 unsynced 存量)
*/
private boolean retryEnabled = false;
}
}
@@ -21,12 +21,12 @@ package org.springblade.transport.listener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.transport.config.BfiProperties;
import org.springblade.transport.event.KingdeeBillApprovedEvent;
import org.springblade.transport.service.IFormalSettlementService;
import org.springblade.transport.service.IInvoiceApplicationService;
import org.springblade.transport.service.IInvoiceReceiptService;
import org.springblade.transport.service.IPaymentApplicationService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
@@ -61,22 +61,7 @@ public class KingdeeApprovalSyncListener {
private final IPaymentApplicationService paymentApplicationService;
private final IInvoiceApplicationService invoiceApplicationService;
private final IInvoiceReceiptService invoiceReceiptService;
/** 结算单审批后自动推 A102-2/A302-2 开关,默认关闭 */
@Value("${thirdParty.bfi.autoSync.settlement:false}")
private boolean settlementEnabled;
/** 付款申请审批后自动推 A103-1/A103-3 开关,默认关闭 */
@Value("${thirdParty.bfi.autoSync.payment:false}")
private boolean paymentEnabled;
/** 开票申请审批后自动推 A303-1 开关,默认关闭 */
@Value("${thirdParty.bfi.autoSync.invoiceApply:false}")
private boolean invoiceApplyEnabled;
/** 收票登记审批后自动推 A303-2+A302-6 开关,默认关闭 */
@Value("${thirdParty.bfi.autoSync.receipt:false}")
private boolean receiptEnabled;
private final BfiProperties bfiProperties;
/** 当前审批请求线程的自动推送失败原因,供 Controller 取走提示前端(见类注释线程说明) */
private static final ThreadLocal<String> SYNC_FAILURE = new ThreadLocal<>();
@@ -118,7 +103,7 @@ public class KingdeeApprovalSyncListener {
}
private void pushSettlement(Long id) {
if (!settlementEnabled) {
if (!bfiProperties.getAutoSync().isSettlement()) {
return;
}
log.info("正式结算单[{}]审批通过自动同步金蝶开始", id);
@@ -127,7 +112,7 @@ public class KingdeeApprovalSyncListener {
}
private void pushPayment(Long id) {
if (!paymentEnabled) {
if (!bfiProperties.getAutoSync().isPayment()) {
return;
}
log.info("付款申请[{}]审批通过自动同步金蝶开始", id);
@@ -136,7 +121,7 @@ public class KingdeeApprovalSyncListener {
}
private void pushInvoiceApply(Long id) {
if (!invoiceApplyEnabled) {
if (!bfiProperties.getAutoSync().isInvoiceApply()) {
return;
}
log.info("开票申请[{}]审批通过自动同步金蝶开始", id);
@@ -145,7 +130,7 @@ public class KingdeeApprovalSyncListener {
}
private void pushReceipt(Long id) {
if (!receiptEnabled) {
if (!bfiProperties.getAutoSync().isReceipt()) {
return;
}
log.info("收票登记[{}]审批通过自动推送金蝶收票单开始", id);
@@ -52,6 +52,7 @@ import org.springblade.thirdparty.bfi.service.IBfiService;
import org.springblade.thirdparty.bfi.util.BfiUtil;
import org.springblade.system.cache.UserCache;
import org.springblade.transport.excel.CustomerArchiveExcel;
import org.springblade.transport.config.BfiProperties;
import org.springblade.transport.mapper.CreditRatingStandardMapper;
import org.springblade.transport.mapper.CreditScoreCategoryMapper;
import org.springblade.transport.mapper.CreditScoreItemMapper;
@@ -92,7 +93,6 @@ import org.springblade.transport.pojo.vo.CustomerInvoiceInfoVO;
import org.springblade.transport.pojo.vo.CustomerReceiptAccountVO;
import org.springblade.transport.service.ICustomerArchiveService;
import org.springblade.transport.support.KingdeeSyncLockSupport;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -219,24 +219,11 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
private final IBfiService bfiService;
private final CustomerBfiConverter customerBfiConverter;
private final KingdeeSyncLockSupport kingdeeSyncLockSupport;
private final BfiProperties bfiProperties;
/** 金蝶客商数据同步 single-flight 锁键前缀(多副本定时任务与手动触发共用) */
private static final String CUSTOMER_SYNC_LOCK_PREFIX = "transport:customer-archive:kingdee-customer-sync:";
/**
* 金蝶客商数据同步 single-flight 锁租约秒数,须大于最坏一轮耗时(复查 + 批量推送 + 停用联动),
* 否则租约到期后另一副本会并发起跑;进程异常退出时锁在租约到期后自动释放
*/
@Value("${thirdParty.bfi.customer.lockLeaseSeconds:1800}")
private long customerSyncLockLeaseSeconds;
/**
* 客商提审命中金蝶黑名单风险警示类(B)时是否一并拦截;
* 默认 false 仅放行告警,禁止交易类(A)始终拦截,与集团合规口径确认后可调整
*/
@Value("${thirdparty.bfi.blacklist.blockRiskWarning:false}")
private boolean blacklistBlockRiskWarning;
@Override
public IPage<CustomerArchiveVO> selectCustomerArchivePage(IPage<CustomerArchiveVO> page, CustomerArchiveVO customer) {
List<CustomerArchiveVO> records = baseMapper.selectCustomerArchivePage(page, customer, currentScopeUserId());
@@ -647,7 +634,7 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
@Override
public String syncKingdeeCustomerData() {
return kingdeeSyncLockSupport.runSingleFlight(CUSTOMER_SYNC_LOCK_PREFIX, customerSyncLockLeaseSeconds,
return kingdeeSyncLockSupport.runSingleFlight(CUSTOMER_SYNC_LOCK_PREFIX, bfiProperties.getCustomer().getLockLeaseSeconds(),
"金蝶客商数据同步", this::executeCustomerDataSync);
}
@@ -1083,7 +1070,7 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
String category = Func.isEmpty(hit.getAwrpCombofieldTitle()) ? hit.getAwrpCombofield() : hit.getAwrpCombofieldTitle();
boolean forbidden = "A".equals(hit.getAwrpCombofield());
boolean riskWarning = "B".equals(hit.getAwrpCombofield());
if (forbidden || (riskWarning && blacklistBlockRiskWarning)) {
if (forbidden || (riskWarning && bfiProperties.getBlacklist().isBlockRiskWarning())) {
throw new ServiceException(String.format("客商【%s】在国资委黑名单中(失信类别:%s,列入事由:%s),不允许提交准入审批",
customer.getFullName(), category, hit.getAwrpTextareafield()));
}
@@ -40,6 +40,7 @@ import org.springblade.transport.mapper.PaymentApplicationInvoiceMapper;
import org.springblade.transport.mapper.PaymentApplicationSettlementMapper;
import org.springblade.transport.mapper.ReceiptClaimSettlementMapper;
import org.springblade.transport.constant.KingdeeAttachmentConstant;
import org.springblade.transport.config.BfiProperties;
import org.springblade.transport.constant.KingdeeBfiConstant;
import org.springblade.transport.constant.KingdeeLockConstant;
import org.springblade.transport.pojo.entity.KingdeeBillLock;
@@ -99,7 +100,6 @@ import org.springblade.transport.event.KingdeeBillApprovedEvent;
import org.springblade.transport.wrapper.FormalSettlementWrapper;
import org.springblade.transport.wrapper.PaymentApplicationWrapper;
import org.springblade.system.cache.UserCache;
import org.springframework.beans.factory.annotation.Value;
import org.springblade.core.tool.utils.SpringUtil;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
@@ -176,13 +176,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
private final KingdeeAttachmentSyncSupport kingdeeAttachmentSyncSupport;
private final KingdeeSyncLockSupport kingdeeSyncLockSupport;
private final ApplicationEventPublisher eventPublisher;
/**
* 金蝶应收单勾稽 single-flight 锁租约秒数,须大于最坏一轮耗时(批量远程查询 + 分批纠偏回写),
* 否则租约到期后另一副本会并发起跑;进程异常退出时锁在租约到期后自动释放
*/
@Value("${thirdParty.bfi.arResult.lockLeaseSeconds:1800}")
private long arResultLockLeaseSeconds;
private final BfiProperties bfiProperties;
@Override
public IPage<FormalSettlementVO> selectPage(IPage<FormalSettlement> page, FormalSettlementVO query) {
@@ -851,7 +845,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
@Override
public String syncKingdeeArResult() {
return kingdeeSyncLockSupport.runSingleFlight(AR_RESULT_SYNC_LOCK_PREFIX, arResultLockLeaseSeconds,
return kingdeeSyncLockSupport.runSingleFlight(AR_RESULT_SYNC_LOCK_PREFIX, bfiProperties.getArResult().getLockLeaseSeconds(),
"金蝶应收单勾稽", this::executeArResultSync);
}
@@ -103,7 +103,6 @@ import org.springblade.transport.support.KingdeeSyncLockSupport;
import org.springblade.transport.support.KingdeeAttachmentSyncSupport;
import org.springblade.transport.wrapper.InvoiceApplicationWrapper;
import org.springblade.transport.wrapper.WaybillWrapper;
import org.springframework.beans.factory.annotation.Value;
import org.springblade.core.tool.utils.SpringUtil;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
@@ -166,13 +165,6 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
/** 金蝶单据锁定记录服务(lockBusiData 锁定/补偿/解锁守卫) */
private final IKingdeeBillLockService kingdeeBillLockService;
/**
* 金蝶开票结果回写 single-flight 锁租约秒数,须大于最坏一轮耗时(分批远程查询 + 逐单回写),
* 否则租约到期后另一副本会并发起跑;进程异常退出时锁在租约到期后自动释放
*/
@Value("${thirdParty.bfi.invoiceResult.lockLeaseSeconds:1800}")
private long invoiceResultLockLeaseSeconds;
@Override
public IPage<InvoiceApplicationVO> selectPage(IPage<InvoiceApplication> page, InvoiceApplicationVO query) {
LambdaQueryWrapper<InvoiceApplication> wrapper = Wrappers.<InvoiceApplication>lambdaQuery()
@@ -1135,7 +1127,7 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
@Override
public String syncKingdeeInvoiceResult() {
return kingdeeSyncLockSupport.runSingleFlight(INVOICE_RESULT_SYNC_LOCK_PREFIX, invoiceResultLockLeaseSeconds,
return kingdeeSyncLockSupport.runSingleFlight(INVOICE_RESULT_SYNC_LOCK_PREFIX, bfiProperties.getInvoiceResult().getLockLeaseSeconds(),
"金蝶开票结果回写", this::executeInvoiceResultSync);
}
@@ -51,6 +51,7 @@ import org.springblade.thirdparty.bfi.pojo.vo.BfiPageVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiReceivedInvoiceVO;
import org.springblade.thirdparty.bfi.service.IBfiService;
import org.springblade.transport.constant.KingdeeAttachmentConstant;
import org.springblade.transport.config.BfiProperties;
import org.springblade.transport.constant.KingdeeBfiConstant;
import org.springblade.transport.constant.TransportBusiConstant;
import org.springblade.transport.event.KingdeeBillApprovedEvent;
@@ -84,7 +85,6 @@ import org.springblade.transport.support.KingdeeAttachmentSyncSupport;
import org.springblade.transport.support.KingdeeReceivedInvoiceSyncSupport;
import org.springblade.transport.support.KingdeeSyncLockSupport;
import org.springblade.transport.wrapper.InvoiceReceiptWrapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -147,6 +147,7 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl<InvoiceReceiptMap
private final CustomerArchiveMapper customerArchiveMapper;
private final CustomerContactMapper customerContactMapper;
private final IBfiService bfiService;
private final BfiProperties bfiProperties;
private final KingdeeApBillSyncSupport kingdeeApBillSyncSupport;
private final KingdeeReceivedInvoiceSyncSupport kingdeeReceivedInvoiceSyncSupport;
private final KingdeeAttachmentSyncSupport kingdeeAttachmentSyncSupport;
@@ -156,29 +157,6 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl<InvoiceReceiptMap
/** 金蝶收票单结果回写 single-flight 锁键前缀(多副本定时任务与手动触发共用) */
private static final String RECEIVED_RESULT_SYNC_LOCK_PREFIX = "transport:invoice-receipt:kingdee-received-result-sync:";
/** A801-3 推送幂等预检回看窗口天数(金蝶修改时间窗口,契约约束不超过 1 个月) */
@Value("${thirdParty.bfi.receivedInvoice.queryWindowDays:30}")
private int receivedQueryWindowDays;
/** A801-3 定时回写轮询窗口天数(同样受金蝶 1 个月窗口约束) */
@Value("${thirdParty.bfi.receivedInvoice.resultWindowDays:30}")
private int receivedResultWindowDays;
/**
* 金蝶收票单结果回写 single-flight 锁租约秒数,须大于最坏一轮耗时(批量远程查询 + 逐单回写),
* 否则租约到期后另一副本会并发起跑;进程异常退出时锁在租约到期后自动释放
*/
@Value("${thirdParty.bfi.receivedInvoice.lockLeaseSeconds:1800}")
private long receivedResultLockLeaseSeconds;
/** A801-1 全票池同步增量窗口天数(按票池更新时间滚动,每轮固定近 N 天,幂等覆盖) */
@Value("${thirdParty.bfi.invoiceReceipt.incrementDays:30}")
private int poolIncrementDays;
/** 金蝶全票池同步 single-flight 锁租约秒数,须大于最坏一轮耗时;进程异常退出时锁在租约到期后自动释放 */
@Value("${thirdParty.bfi.invoiceReceipt.lockLeaseSeconds:1800}")
private long poolSyncLockLeaseSeconds;
@Override
public IPage<InvoiceReceiptVO> selectPage(IPage<InvoiceReceipt> page, InvoiceReceiptVO query) {
LambdaQueryWrapper<InvoiceReceipt> wrapper = Wrappers.<InvoiceReceipt>lambdaQuery()
@@ -870,7 +848,7 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl<InvoiceReceiptMap
}
Map<String, BfiReceivedInvoiceVO> rows = new LinkedHashMap<>();
LocalDateTime windowEnd = LocalDateTime.now();
LocalDateTime windowStart = windowEnd.minusDays(Math.max(receivedQueryWindowDays, 1));
LocalDateTime windowStart = windowEnd.minusDays(Math.max(bfiProperties.getReceivedInvoice().getQueryWindowDays(), 1));
for (Map.Entry<String, Set<String>> entry : invoiceNosByBuyer.entrySet()) {
if (StringUtil.isBlank(entry.getKey())) {
continue;
@@ -939,7 +917,7 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl<InvoiceReceiptMap
@Override
public String syncKingdeeReceivedInvoiceResult() {
return kingdeeSyncLockSupport.runSingleFlight(RECEIVED_RESULT_SYNC_LOCK_PREFIX, receivedResultLockLeaseSeconds,
return kingdeeSyncLockSupport.runSingleFlight(RECEIVED_RESULT_SYNC_LOCK_PREFIX, bfiProperties.getReceivedInvoice().getLockLeaseSeconds(),
"金蝶收票单结果回写", this::executeReceivedInvoiceResultSync);
}
@@ -951,7 +929,7 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl<InvoiceReceiptMap
* ③ 单号补登——assigned 终态缺失金蝶收票单号(保存成功但响应丢失的历史数据)时仅补登单号,不改变状态。
* <p>匹配与容错说明:
* ① 匹配键为收票登记 id,与 A303-2 落库的 awrp_src_code 同源,按发票号匹配将永远查不到自推单据;
* ② 查询窗口为近 {@code receivedResultWindowDays} 天(至少 1 天),窗口内查不到不判为金蝶侧已删除
* ② 查询窗口为近 {@code thirdparty.bfi.receivedInvoice.resultWindowDays} 配置天数(至少 1 天),窗口内查不到不判为金蝶侧已删除
* (金蝶修改时间延迟/滑窗),保持现状由人工重推兜底;
* ③ 单笔回写异常仅记入失败明细不中断整轮,结束时汇总进执行摘要;
* ④ 由 {@link #syncKingdeeReceivedInvoiceResult()} 在分布式锁保护下调用,防多实例并发重跑。
@@ -994,7 +972,7 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl<InvoiceReceiptMap
receiptsByBuyer.computeIfAbsent(mirror.getReceiverName().trim(), key -> new ArrayList<>()).add(receipt);
}
LocalDateTime windowEnd = LocalDateTime.now();
LocalDateTime windowStart = windowEnd.minusDays(Math.max(receivedResultWindowDays, 1));
LocalDateTime windowStart = windowEnd.minusDays(Math.max(bfiProperties.getReceivedInvoice().getResultWindowDays(), 1));
int recovered = 0;
int reassigned = 0;
int filled = 0;
@@ -1248,14 +1226,10 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl<InvoiceReceiptMap
@Override
public String syncKingdeeInvoicePool() {
return kingdeeSyncLockSupport.runSingleFlight(POOL_SYNC_LOCK_PREFIX, poolSyncLockLeaseSeconds,
return kingdeeSyncLockSupport.runSingleFlight(POOL_SYNC_LOCK_PREFIX, bfiProperties.getInvoiceReceipt().getLockLeaseSeconds(),
"金蝶全票池同步", this::executePoolSync);
}
/** 发票种类白名单(thirdParty.bfi.invoiceReceipt.invoiceTypes 逗号分隔票易通编码,如 26,27),为空不限制 */
@Value("${thirdParty.bfi.invoiceReceipt.invoiceTypes:}")
private String poolInvoiceTypes;
/**
* 同步主体(39ffac1 绑定回填口径瘦身版):滚动增量窗口按 updateTime **切片续扫** + 镜像批量 upsert(有变化才写)
* + 未绑定存量登记顺带补绑(同页发票号码批量定位登记,页级事务批量落库)。
@@ -1271,7 +1245,7 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl<InvoiceReceiptMap
*/
private String executePoolSync() {
long startMillis = System.currentTimeMillis();
LocalDateTime windowStart = LocalDateTime.now().minusDays(poolIncrementDays);
LocalDateTime windowStart = LocalDateTime.now().minusDays(bfiProperties.getInvoiceReceipt().getIncrementDays());
LocalDateTime windowEnd = LocalDateTime.now();
List<String> invoiceTypes = this.poolInvoiceTypeCodes();
SyncStats stats = new SyncStats();
@@ -1296,10 +1270,10 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl<InvoiceReceiptMap
/** 白名单编码集:逗号分隔配置解析 trim,空配置返回空集(不限制) */
private List<String> poolInvoiceTypeCodes() {
if (StringUtil.isBlank(poolInvoiceTypes)) {
if (StringUtil.isBlank(bfiProperties.getInvoiceReceipt().getInvoiceTypes())) {
return List.of();
}
return java.util.Arrays.stream(poolInvoiceTypes.split(","))
return java.util.Arrays.stream(bfiProperties.getInvoiceReceipt().getInvoiceTypes().split(","))
.map(String::trim)
.filter(StringUtil::isNotBlank)
.distinct()
@@ -103,7 +103,6 @@ import org.springblade.transport.support.KingdeeApBillSyncSupport;
import org.springblade.transport.support.KingdeeAttachmentSyncSupport;
import org.springblade.transport.support.KingdeeSyncLockSupport;
import org.springblade.transport.wrapper.PaymentApplicationWrapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -169,13 +168,6 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
private final BladeRedis bladeRedis;
private final ApplicationEventPublisher eventPublisher;
/**
* 金蝶付款结果回写 single-flight 锁租约秒数,须大于最坏一轮耗时(分批远程查询 + 逐单回写),
* 否则租约到期后另一副本会并发起跑;进程异常退出时锁在租约到期后自动释放
*/
@Value("${thirdParty.bfi.payResult.lockLeaseSeconds:1800}")
private long payResultLockLeaseSeconds;
@Override
public IPage<PaymentApplicationVO> selectPage(IPage<PaymentApplication> page, PaymentApplicationVO query) {
LambdaQueryWrapper<PaymentApplication> wrapper = Wrappers.<PaymentApplication>lambdaQuery()
@@ -731,7 +723,7 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
@Override
public String syncKingdeePaymentResult() {
return kingdeeSyncLockSupport.runSingleFlight(PAY_RESULT_SYNC_LOCK_PREFIX, payResultLockLeaseSeconds,
return kingdeeSyncLockSupport.runSingleFlight(PAY_RESULT_SYNC_LOCK_PREFIX, bfiProperties.getPayResult().getLockLeaseSeconds(),
"金蝶付款结果回写", this::executePaymentResultSync);
}
@@ -66,7 +66,6 @@ import org.springblade.transport.service.IReceiptFlowService;
import org.springblade.transport.support.KingdeeSyncLockSupport;
import org.springblade.transport.support.TransportBusinessSupport;
import org.springblade.transport.wrapper.ReceiptFlowWrapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
@@ -132,13 +131,6 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl<KingdeeReceiptFlowMa
private final TransactionTemplate transactionTemplate;
private final KingdeeSyncLockSupport kingdeeSyncLockSupport;
/**
* 定时推送收款认领 single-flight 锁租约秒数,须大于最坏一轮耗时(逐认领人远程查公告 + 逐条推送),
* 否则租约到期后另一副本会并发起跑;进程异常退出时锁在租约到期后自动释放
*/
@Value("${thirdParty.bfi.receiptClaimPush.lockLeaseSeconds:1800}")
private long receiptClaimPushLockLeaseSeconds;
@Override
public IPage<ReceiptFlowVO> selectPage(IPage<KingdeeReceiptFlow> page, ReceiptFlowVO query) {
LambdaQueryWrapper<KingdeeReceiptFlow> wrapper = Wrappers.<KingdeeReceiptFlow>lambdaQuery()
@@ -712,7 +704,7 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl<KingdeeReceiptFlowMa
*/
@Override
public String pushClaimByTask() {
return kingdeeSyncLockSupport.runSingleFlight(RECEIPT_CLAIM_PUSH_LOCK_PREFIX, receiptClaimPushLockLeaseSeconds,
return kingdeeSyncLockSupport.runSingleFlight(RECEIPT_CLAIM_PUSH_LOCK_PREFIX, bfiProperties.getReceiptClaimPush().getLockLeaseSeconds(),
"定时推送收款认领", this::executeReceiptClaimPush);
}
@@ -27,8 +27,8 @@ package org.springblade.transport.task;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.transport.config.BfiProperties;
import org.springblade.transport.service.ICustomerArchiveService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -51,15 +51,12 @@ import org.springframework.stereotype.Component;
public class CustomerKingdeeSyncTask {
private final ICustomerArchiveService customerArchiveService;
/** 客商金蝶数据同步开关,默认关闭 */
@Value("${thirdParty.bfi.customer.syncEnabled:false}")
private boolean syncEnabled;
private final BfiProperties bfiProperties;
/** 客商金蝶数据同步调度,默认每天 02:00 执行 */
@Scheduled(cron = "${thirdParty.bfi.customer.cron:0 0 2 * * ?}")
public void syncKingdeeCustomerData() {
if (!syncEnabled) {
if (!bfiProperties.getCustomer().isSyncEnabled()) {
return;
}
try {
@@ -26,8 +26,8 @@ package org.springblade.transport.task;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.transport.config.BfiProperties;
import org.springblade.transport.service.IInvoiceReceiptService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -48,15 +48,12 @@ import org.springframework.stereotype.Component;
public class InvoiceReceiptKingdeeSyncTask {
private final IInvoiceReceiptService invoiceReceiptService;
/** 全票池同步任务开关,默认关闭(上线先手动跑一次 bootstrap 铺底,联调稳定后开启) */
@Value("${thirdParty.bfi.invoiceReceipt.syncEnabled:false}")
private boolean syncEnabled;
private final BfiProperties bfiProperties;
/** 金蝶全票池同步调度,默认每30分钟执行一次 */
@Scheduled(cron = "${thirdParty.bfi.invoiceReceipt.cron:0 */30 * * * ?}")
public void syncKingdeeInvoicePool() {
if (!syncEnabled) {
if (!bfiProperties.getInvoiceReceipt().isSyncEnabled()) {
return;
}
try {
@@ -21,11 +21,11 @@ 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.springblade.transport.service.IInvoiceApplicationService;
import org.springblade.transport.service.IInvoiceReceiptService;
import org.springblade.transport.service.IPaymentApplicationService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -52,15 +52,12 @@ public class KingdeeAutoSyncRetryTask {
private final IFormalSettlementService formalSettlementService;
private final IInvoiceApplicationService invoiceApplicationService;
private final IInvoiceReceiptService invoiceReceiptService;
/** failed 重推开关,代码默认关闭(安全兜底),由 Nacos thirdParty.bfi.autoSync.retryEnabled 按环境显式开启 */
@Value("${thirdParty.bfi.autoSync.retryEnabled:false}")
private boolean retryEnabled;
private final BfiProperties bfiProperties;
/** failed 定时重推调度,默认每10分钟执行一次 */
@Scheduled(cron = "${thirdParty.bfi.autoSync.retryCron:0 */10 * * * ?}")
public void retryKingdeeFailed() {
if (!retryEnabled) {
if (!bfiProperties.getAutoSync().isRetryEnabled()) {
return;
}
// ① 结算单(A102-2/A302-2)
@@ -10,8 +10,8 @@ package org.springblade.transport.task;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.transport.config.BfiProperties;
import org.springblade.transport.service.IKingdeeBillLockService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -32,15 +32,12 @@ import org.springframework.stereotype.Component;
public class KingdeeBillLockRetryTask {
private final IKingdeeBillLockService kingdeeBillLockService;
/** 锁定补偿开关,代码默认关闭(安全兜底),由 Nacos thirdParty.bfi.billLock.retryEnabled 按环境显式开启 */
@Value("${thirdParty.bfi.billLock.retryEnabled:false}")
private boolean retryEnabled;
private final BfiProperties bfiProperties;
/** 锁定补偿调度,默认每5分钟执行一次 */
@Scheduled(cron = "${thirdParty.bfi.billLock.retryCron:0 */5 * * * ?}")
public void retryFailedBillLocks() {
if (!retryEnabled) {
if (!bfiProperties.getBillLock().isRetryEnabled()) {
return;
}
try {
@@ -21,11 +21,11 @@ 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.springblade.transport.service.IInvoiceApplicationService;
import org.springblade.transport.service.IInvoiceReceiptService;
import org.springblade.transport.service.IPaymentApplicationService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -54,15 +54,12 @@ public class PaymentKingdeeResultTask {
private final IFormalSettlementService formalSettlementService;
private final IInvoiceApplicationService invoiceApplicationService;
private final IInvoiceReceiptService invoiceReceiptService;
/** 付款结果回写开关,代码默认关闭(安全兜底),由 Nacos thirdParty.bfi.payResult.syncEnabled 按环境显式开启 */
@Value("${thirdParty.bfi.payResult.syncEnabled:false}")
private boolean syncEnabled;
private final BfiProperties bfiProperties;
/** 金蝶结果回写调度,默认每10分钟执行一次 */
@Scheduled(cron = "${thirdParty.bfi.payResult.cron:0 */10 * * * ?}")
public void syncKingdeePaymentResult() {
if (!syncEnabled) {
if (!bfiProperties.getPayResult().isSyncEnabled()) {
return;
}
// ① A103-2/A103-4 付款结果回写
@@ -88,14 +85,10 @@ public class PaymentKingdeeResultTask {
}
}
/** 金蝶收票单结果回写开关(A801-3),默认关闭(联调稳定后开启) */
@Value("${thirdParty.bfi.receivedInvoiceResult.syncEnabled:false}")
private boolean receivedInvoiceResultEnabled;
/** 金蝶收票单结果回写调度(异常回收/指定补偿/单号补登),默认每10分钟执行一次 */
@Scheduled(cron = "${thirdParty.bfi.receivedInvoiceResult.cron:0 */10 * * * ?}")
public void syncKingdeeReceivedInvoiceResult() {
if (!receivedInvoiceResultEnabled) {
if (!bfiProperties.getReceivedInvoiceResult().isSyncEnabled()) {
return;
}
try {
@@ -27,8 +27,8 @@ package org.springblade.transport.task;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.transport.config.BfiProperties;
import org.springblade.transport.service.IReceiptFlowService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -49,15 +49,12 @@ import org.springframework.stereotype.Component;
public class ReceiptClaimPushTask {
private final IReceiptFlowService receiptFlowService;
/** 收款认领推送开关,默认关闭(联调稳定后开启) */
@Value("${thirdParty.bfi.receiptClaimPush.syncEnabled:false}")
private boolean syncEnabled;
private final BfiProperties bfiProperties;
/** 收款认领推送调度,默认每10分钟执行一次 */
@Scheduled(cron = "${thirdParty.bfi.receiptClaimPush.cron:0 */10 * * * ?}")
public void pushClaimToKingdee() {
if (!syncEnabled) {
if (!bfiProperties.getReceiptClaimPush().isSyncEnabled()) {
return;
}
try {
+18
View File
@@ -102,5 +102,23 @@ thirdParty:
cron: ${BFI_INVOICE_RECEIPT_CRON:0 */30 * * * ?}
# 增量窗口天数(按票池更新时间滚动)
incrementDays: ${BFI_INVOICE_RECEIPT_INCREMENT_DAYS:30}
# 同步发票种类白名单(逗号分隔票易通编码,如 26,27 数电普票/专票),为空不限制
invoiceTypes: ${BFI_INVOICE_RECEIPT_INVOICE_TYPES:26,27}
# 补偿绑定单轮限量(未绑定登记按发票号码精确补查条数上限)
compensateLimit: ${BFI_INVOICE_RECEIPT_COMPENSATE_LIMIT:200}
# single-flight 分布式锁租约秒数,须大于最坏一轮耗时;进程异常退出时锁在租约到期后自动释放
lockLeaseSeconds: ${BFI_INVOICE_RECEIPT_LOCK_LEASE_SECONDS:1800}
# 审批通过自动同步金蝶(事件触发:结算单A102-2/A302-2、付款申请A103-1/A103-3、开票申请A303-1、收票A303-2+A302-6)
autoSync:
# 结算单审批后自动推送开关
settlement: ${BFI_AUTO_SYNC_SETTLEMENT:false}
# 付款申请审批后自动推送开关
payment: ${BFI_AUTO_SYNC_PAYMENT:false}
# 开票申请审批后自动推送开关
invoiceApply: ${BFI_AUTO_SYNC_INVOICE_APPLY:false}
# 收票登记审批后自动推送开关
receipt: ${BFI_AUTO_SYNC_RECEIPT:false}
# failed 单据定时重推开关(仅重推生成失败,不扫 unsynced 存量)
retryEnabled: ${BFI_AUTO_SYNC_RETRY_ENABLED:false}
# 重推调度 cron,默认每10分钟
retryCron: ${BFI_AUTO_SYNC_RETRY_CRON:0 */10 * * * ?}