fix: 付款同步金蝶增加财务应付单防重预检与单据编号回填
- A102-2 推送前经 A102-4 按防重键(awrp_src_sys + awrp_src_code)幂等预检,已生成时终止推送并提示用户 - 财务应付单单据编号推送成功后即时回填 kingdeeBillNo - 批量同步整批一次 A102-4 预检并缓存结果(KingdeeSyncContext 新增应付单/结算明细缓存),消除逐单远程查询与明细重复查询 - doSyncKingdee 补充开始/跳过/推送/完成关键节点日志
This commit is contained in:
+6
-2
@@ -25,9 +25,11 @@
|
||||
package org.springblade.transport.service;
|
||||
|
||||
import org.springblade.transport.pojo.entity.ContractManage;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementDetail;
|
||||
import org.springblade.transport.pojo.entity.ProjectApply;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -37,10 +39,12 @@ import java.util.Map;
|
||||
* @author Chill
|
||||
*/
|
||||
public record KingdeeSyncContext(Map<String, String> cargoCodeByName, Map<Long, ContractManage> contractCache,
|
||||
Map<String, String> customerCodeCache, Map<Long, ProjectApply> projectCache) {
|
||||
Map<String, String> customerCodeCache, Map<Long, ProjectApply> projectCache,
|
||||
Map<String, String> apBillNoCache,
|
||||
Map<Long, List<FormalSettlementDetail>> settlementDetailCache) {
|
||||
|
||||
/** 空上下文:缓存可写但初始为空,首条记录命中后全批复用 */
|
||||
public static KingdeeSyncContext empty() {
|
||||
return new KingdeeSyncContext(new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||
return new KingdeeSyncContext(new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||
}
|
||||
}
|
||||
|
||||
+138
-31
@@ -27,19 +27,18 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.mp.base.BaseServiceImpl;
|
||||
import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.jackson.JsonUtil;
|
||||
import org.springblade.core.tool.utils.BeanUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.SpringUtil;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.transport.constant.KingdeeBfiConstant;
|
||||
import org.springblade.transport.constant.TransportBusiConstant;
|
||||
import org.springblade.system.cache.DictBizCache;
|
||||
import org.springblade.system.cache.SysCache;
|
||||
import org.springblade.system.feign.ISysClient;
|
||||
import org.springblade.system.pojo.entity.CargoType;
|
||||
import org.springblade.system.pojo.entity.DictBiz;
|
||||
import org.springblade.system.pojo.entity.Dept;
|
||||
import org.springblade.system.pojo.entity.DictBiz;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillQueryDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillSaveDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillSaveEntryDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiPayApplyPushDTO;
|
||||
@@ -48,6 +47,7 @@ import org.springblade.thirdparty.bfi.pojo.dto.BfiPayApplyQueryDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiPayApplySaveDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiPayApplySaveEntryDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiPayBillQueryDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.vo.BfiApBillVO;
|
||||
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultItemVO;
|
||||
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultVO;
|
||||
import org.springblade.thirdparty.bfi.pojo.vo.BfiPayApplyEntryVO;
|
||||
@@ -55,53 +55,55 @@ import org.springblade.thirdparty.bfi.pojo.vo.BfiPayApplyVO;
|
||||
import org.springblade.thirdparty.bfi.pojo.vo.BfiPayBillVO;
|
||||
import org.springblade.thirdparty.bfi.service.IBfiService;
|
||||
import org.springblade.thirdparty.bfi.util.BfiUtil;
|
||||
import org.springblade.transport.constant.KingdeeBfiConstant;
|
||||
import org.springblade.transport.constant.TransportBusiConstant;
|
||||
import org.springblade.transport.mapper.BillLedgerMapper;
|
||||
import org.springblade.transport.mapper.BillLedgerUsageMapper;
|
||||
import org.springblade.transport.mapper.ContractManageMapper;
|
||||
import org.springblade.transport.mapper.CustomerArchiveMapper;
|
||||
import org.springblade.transport.mapper.FormalSettlementDetailFeeMapper;
|
||||
import org.springblade.transport.mapper.FormalSettlementDetailMapper;
|
||||
import org.springblade.transport.mapper.FormalSettlementMapper;
|
||||
import org.springblade.transport.mapper.FormalSettlementPaymentMapper;
|
||||
import org.springblade.transport.mapper.BillLedgerMapper;
|
||||
import org.springblade.transport.mapper.BillLedgerUsageMapper;
|
||||
import org.springblade.transport.mapper.PreSettlementMapper;
|
||||
import org.springblade.transport.mapper.ProjectApplyMapper;
|
||||
import org.springblade.transport.mapper.CustomerArchiveMapper;
|
||||
import org.springblade.transport.mapper.ContractManageMapper;
|
||||
import org.springblade.transport.mapper.FormalSettlementSourceMapper;
|
||||
import org.springblade.transport.mapper.PaymentApplicationInvoiceMapper;
|
||||
import org.springblade.transport.mapper.PaymentApplicationMapper;
|
||||
import org.springblade.transport.mapper.PaymentApplicationRecordMapper;
|
||||
import org.springblade.transport.mapper.PaymentApplicationSettlementMapper;
|
||||
import org.springblade.transport.mapper.FormalSettlementSourceMapper;
|
||||
import org.springblade.transport.mapper.PreSettlementAdvanceMapper;
|
||||
import org.springblade.transport.mapper.PreSettlementMapper;
|
||||
import org.springblade.transport.mapper.ProjectApplyMapper;
|
||||
import org.springblade.transport.mapper.TemporaryCreditLimitMapper;
|
||||
import org.springblade.transport.pojo.dto.PaymentApplicationInvoiceRequest;
|
||||
import org.springblade.transport.pojo.dto.PaymentApplicationRecordRequest;
|
||||
import org.springblade.transport.pojo.dto.PaymentApplicationSaveRequest;
|
||||
import org.springblade.transport.pojo.dto.PaymentApplicationStatusRequest;
|
||||
import org.springblade.transport.pojo.entity.BillLedger;
|
||||
import org.springblade.transport.pojo.entity.BillLedgerUsage;
|
||||
import org.springblade.transport.pojo.entity.ContractManage;
|
||||
import org.springblade.transport.pojo.entity.CustomerArchive;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlement;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementDetail;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementDetailFee;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementPayment;
|
||||
import org.springblade.transport.pojo.entity.BillLedger;
|
||||
import org.springblade.transport.pojo.entity.BillLedgerUsage;
|
||||
import org.springblade.transport.pojo.entity.PreSettlement;
|
||||
import org.springblade.transport.pojo.entity.ProjectApply;
|
||||
import org.springblade.transport.pojo.entity.CustomerArchive;
|
||||
import org.springblade.transport.pojo.entity.ContractManage;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementSource;
|
||||
import org.springblade.transport.pojo.entity.PaymentApplication;
|
||||
import org.springblade.transport.pojo.entity.PaymentApplicationInvoice;
|
||||
import org.springblade.transport.pojo.entity.PaymentApplicationRecord;
|
||||
import org.springblade.transport.pojo.entity.PaymentApplicationSettlement;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementSource;
|
||||
import org.springblade.transport.pojo.entity.PreSettlement;
|
||||
import org.springblade.transport.pojo.entity.PreSettlementAdvance;
|
||||
import org.springblade.transport.pojo.entity.ProjectApply;
|
||||
import org.springblade.transport.pojo.entity.TemporaryCreditLimit;
|
||||
import org.springblade.transport.pojo.vo.PaymentApplicationVO;
|
||||
import org.springblade.transport.pojo.vo.PaymentApplicationReferenceAmountVO;
|
||||
import org.springblade.transport.pojo.vo.PaymentApplicationVO;
|
||||
import org.springblade.transport.service.IFormalSettlementService;
|
||||
import org.springblade.transport.service.IPaymentApplicationService;
|
||||
import org.springblade.transport.service.KingdeeSyncContext;
|
||||
import org.springblade.transport.service.IFormalSettlementService;
|
||||
import org.springblade.transport.support.ExternalSrcCodeSupport;
|
||||
import org.springblade.transport.wrapper.PaymentApplicationWrapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@@ -387,8 +389,12 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
|| KingdeeBfiConstant.KINGDEE_STATUS_PAID.equals(entity.getKingdeeStatus())
|
||||
|| KingdeeBfiConstant.KINGDEE_STATUS_CLOSED.equals(entity.getKingdeeStatus())) {
|
||||
// 存量数据金蝶单据id可能仍存于 kingdeeBillNo,兜底返回
|
||||
return Func.isNotEmpty(entity.getKingdeeBillId()) ? entity.getKingdeeBillId() : entity.getKingdeeBillNo();
|
||||
String existBillId = Func.isNotEmpty(entity.getKingdeeBillId()) ? entity.getKingdeeBillId() : entity.getKingdeeBillNo();
|
||||
log.info("付款申请[{}]金蝶单据已生成(状态[{}]),跳过重复推送,返回单据id={}", entity.getPaymentNo(), entity.getKingdeeStatus(), existBillId);
|
||||
return existBillId;
|
||||
}
|
||||
log.info("付款申请[{}]开始同步金蝶:paymentType={},申请金额={},kingdeeStatus={}",
|
||||
entity.getPaymentNo(), entity.getPaymentType(), entity.getAppliedAmount(), entity.getKingdeeStatus());
|
||||
String kingdeeBillId;
|
||||
if (TransportBusiConstant.PAYMENT_TYPE_SETTLEMENT.equals(entity.getPaymentType())) {
|
||||
// 单据类型路由:按正式结算单结算类型——应付对应财务应付单(A102-2),应收对应财务应收单(A302-2,推送规则待业务确认)
|
||||
@@ -398,15 +404,20 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
// 分录按结算明细货物编码+计量单位分组拆分(物料编码取货物类型档案编码、计量单位暂传货物单位、
|
||||
// 数量取组内运输数量合计),财务应付单 detailentry 与付款申请 entry 一一对应
|
||||
BfiEntryGroupResult entryGroupResult = resolveBfiEntryGroups(entity, context);
|
||||
log.info("付款申请[{}]正式结算付款:开始推送金蝶财务应付单(A102-2),分录组{}条", entity.getPaymentNo(), entryGroupResult.entryGroups().size());
|
||||
String apBillNo = pushBfiApBill(entity, entryGroupResult.entryGroups(), entryGroupResult.documentNos(), context);
|
||||
// 财务应付单单据编号即时回填 kingdeeBillNo(后续付款申请单编号经 A103-2 定时回写任务覆盖)
|
||||
if (Func.isNotEmpty(apBillNo)) {
|
||||
entity.setKingdeeBillNo(apBillNo);
|
||||
}
|
||||
log.info("付款申请[{}]金蝶财务应付单(A102-2)推送成功,单据编号[{}]已回填 kingdeeBillNo", entity.getPaymentNo(), apBillNo);
|
||||
kingdeeBillId = pushBfiPayApplyPush(entity, entryGroupResult.entryGroups(), context);
|
||||
log.info("付款申请[{}]金蝶付款申请单(A103-1 应付下推)推送成功:kingdeeBillId={}", entity.getPaymentNo(), kingdeeBillId);
|
||||
} else {
|
||||
// 预付款:直接推付款申请单(A103-3),不绑应付单
|
||||
log.info("付款申请[{}]预付款:直接推送金蝶付款申请单(A103-3)", entity.getPaymentNo());
|
||||
kingdeeBillId = pushBfiPayApply(entity, context);
|
||||
log.info("付款申请[{}]金蝶付款申请单(A103-3)推送成功:kingdeeBillId={}", entity.getPaymentNo(), kingdeeBillId);
|
||||
}
|
||||
// 星瀚单据内部主键落 kingdeeBillId(附件上传等使用);
|
||||
// 财务应付单单据编号已在推送时回填 kingdeeBillNo,付款申请单编号与付款状态由定时回写任务经 A103-2/A103-4 查询回填
|
||||
@@ -419,6 +430,8 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
// syncPreSettlementAdvance(entity);
|
||||
// syncFormalSettlementPayments(entity);
|
||||
updateById(entity);
|
||||
log.info("付款申请[{}]同步金蝶完成:kingdeeStatus={},kingdeeBillId={},kingdeeBillNo={}",
|
||||
entity.getPaymentNo(), entity.getKingdeeStatus(), kingdeeBillId, entity.getKingdeeBillNo());
|
||||
return kingdeeBillId;
|
||||
}
|
||||
|
||||
@@ -440,6 +453,8 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
if (distinctIds.isEmpty()) throw new ServiceException("请至少选择一条审批通过的付款申请");
|
||||
// 全批共享档案缓存(货物类型/合同/客商/项目),首单加载后全批复用,消除逐单重复查询(N+1)
|
||||
KingdeeSyncContext context = KingdeeSyncContext.empty();
|
||||
// 批量预检财务应付单是否已生成:整批一次 A102-4 批量查询,结果入缓存供逐单推送复用
|
||||
preloadApBillExistNos(distinctIds, context);
|
||||
IPaymentApplicationService self = SpringUtil.getBean(IPaymentApplicationService.class);
|
||||
List<String> result = new ArrayList<>();
|
||||
for (Long id : distinctIds) {
|
||||
@@ -666,6 +681,37 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A102-4 批量查询已生成财务应付单:来源单据号批量 + 外部系统编号(防重键),自动翻页,
|
||||
* 用于推送前幂等预检(awrp_src_code 支持多值,整批一次查询消除逐单远程查询 N+1)
|
||||
*
|
||||
* @param awrpSrcCodes 来源单据号(付款申请号_结算明细单据号拼接)批次
|
||||
* @return 已生成财务应付单的 来源单据号->单据编号 映射
|
||||
*/
|
||||
private Map<String, String> queryApBillExistNos(List<String> awrpSrcCodes) {
|
||||
Map<String, String> existBillNos = new LinkedHashMap<>();
|
||||
// 防重键批量分批查询,避免单次过滤条件过长
|
||||
for (int from = 0; from < awrpSrcCodes.size(); from += PAY_RESULT_QUERY_BATCH) {
|
||||
List<String> batch = awrpSrcCodes.subList(from, Math.min(from + PAY_RESULT_QUERY_BATCH, awrpSrcCodes.size()));
|
||||
if (batch.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
BfiApBillQueryDTO param = new BfiApBillQueryDTO();
|
||||
param.setAwrpSrcCode(batch);
|
||||
param.setAwrpSrcSys(bfiPayApplySrcSys);
|
||||
for (BfiApBillVO apBill : BfiUtil.queryAllPages(pageNo -> {
|
||||
param.setPageNo(pageNo);
|
||||
param.setPageSize(PAY_RESULT_PAGE_SIZE);
|
||||
return bfiService.queryApBill(param);
|
||||
})) {
|
||||
if (Func.isNotEmpty(apBill.getAwrpSrcCode())) {
|
||||
existBillNos.put(apBill.getAwrpSrcCode(), apBill.getBillno());
|
||||
}
|
||||
}
|
||||
}
|
||||
return existBillNos;
|
||||
}
|
||||
|
||||
/**
|
||||
* A103-4 分页查询:按付款人(公司)编码 + 最近1个月业务日期窗口(接口限制不超过1个月),自动翻页
|
||||
*
|
||||
@@ -810,6 +856,7 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
|
||||
/**
|
||||
* 推送金蝶财务应付单(A102-2 财务应付单保存,正式结算付款第一步),仅校验保存成功。
|
||||
* 推送前先经 A102-4 按防重键(awrp_src_sys + awrp_src_code)查询,金蝶已存在财务应付单时终止推送并提示用户。
|
||||
* 明细分录按结算明细货物编码+计量单位分组推送,金额取各组结算金额(含税/不含税)。
|
||||
*
|
||||
* @param entity 付款申请实体
|
||||
@@ -818,6 +865,14 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
* @return 财务应付单金蝶单据编号(返回结果 number 字段),用于回填 kingdeeBillNo
|
||||
*/
|
||||
private String pushBfiApBill(PaymentApplication entity, List<BfiEntryGroup> entryGroups, List<String> documentNos, KingdeeSyncContext context) {
|
||||
// A102-4 幂等预检:按防重键查询金蝶是否已生成财务应付单(批量同步时整批已预热缓存,此处仅懒加载未命中编码),已处理则终止后续推送流程并提示用户
|
||||
String apBillSrcCode = ExternalSrcCodeSupport.buildSrcCode(entity.getPaymentNo(), documentNos);
|
||||
String existBillNo = context.apBillNoCache().computeIfAbsent(apBillSrcCode, code ->
|
||||
queryApBillExistNos(List.of(code)).getOrDefault(code, ""));
|
||||
if (Func.isNotEmpty(existBillNo)) {
|
||||
throw new ServiceException("推送金蝶失败:付款申请[" + entity.getPaymentNo() + "]的财务应付单已生成"
|
||||
+ (Func.isBlank(existBillNo) ? "" : "(单据编号" + existBillNo + ")") + ",请勿重复推送");
|
||||
}
|
||||
ContractManage contract = requireContract(entity, context);
|
||||
// 单据类型按映射字典转换:默认服务采购应付,金蝶确认其他类型后修改 BFI_AP_BILL_BILLTYPE_NAME 即可
|
||||
String billtypeNumber = KingdeeBfiConstant.billtypeBy(KingdeeBfiConstant.AP_BILL_BILLTYPE_MAP, KingdeeBfiConstant.BFI_AP_BILL_BILLTYPE_NAME);
|
||||
@@ -866,8 +921,8 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
// param.setRemark(entity.getPaymentNo() + (Func.isEmpty(entity.getSettlementNo()) ? "" : " " + entity.getSettlementNo()));
|
||||
// 【必填】外部系统编号(候选键)
|
||||
param.setAwrpSrcSys(bfiPayApplySrcSys);
|
||||
// 【必填】外部系统来源单据号(候选键):付款申请号_结算明细单据号1_单据号2...
|
||||
param.setAwrpSrcCode(ExternalSrcCodeSupport.buildSrcCode(entity.getPaymentNo(), documentNos));
|
||||
// 【必填】外部系统来源单据号(候选键):付款申请号_结算明细单据号1_单据号2...(复用预检已组装的防重键)
|
||||
param.setAwrpSrcCode(apBillSrcCode);
|
||||
// 来源单据(非必传,有上游合同时传 awrp_contract_info)
|
||||
// param.setAwrpSrcBt(KingdeeBfiConstant.BFI_CONTRACT_SRC_BT);
|
||||
// 上游外部系统单据号/上游合同号(非必传)
|
||||
@@ -1009,17 +1064,12 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
* @return 应付单分录解析结果(分录组 + 结算明细单据号)
|
||||
*/
|
||||
private BfiEntryGroupResult resolveBfiEntryGroups(PaymentApplication entity, KingdeeSyncContext context) {
|
||||
List<FormalSettlementDetail> settlementDetails = formalSettlementDetails(entity);
|
||||
List<FormalSettlementDetail> settlementDetails = settlementDetails(entity, context);
|
||||
if (Func.isEmpty(settlementDetails)) {
|
||||
throw new ServiceException("推送金蝶财务应付单失败:正式结算单无结算明细,无法解析物料与计量单位");
|
||||
}
|
||||
// 去重收集结算明细单据号(保持行序),用于拼接财务应付单外部系统来源单据号
|
||||
List<String> documentNos = settlementDetails.stream()
|
||||
.map(FormalSettlementDetail::getDocumentNo)
|
||||
.filter(Func::isNotBlank)
|
||||
.map(String::trim)
|
||||
.distinct()
|
||||
.toList();
|
||||
List<String> documentNos = settlementDocumentNos(settlementDetails);
|
||||
Map<String, String> cargoCodeByName = cargoCodeByName(context);
|
||||
LinkedHashMap<String, BfiEntryGroup> groupMap = new LinkedHashMap<>();
|
||||
// 优先按货物费用行逐条取数(blade_formal_settlement_detail_fee 每货物一条,金额为结算调整后的精确值)
|
||||
@@ -1047,6 +1097,63 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
return new BfiEntryGroupResult(new ArrayList<>(groupMap.values()), documentNos);
|
||||
}
|
||||
|
||||
/** 结算明细单据号去重收集(保持行序),用于拼接财务应付单外部系统来源单据号 */
|
||||
private List<String> settlementDocumentNos(List<FormalSettlementDetail> settlementDetails) {
|
||||
return settlementDetails.stream()
|
||||
.map(FormalSettlementDetail::getDocumentNo)
|
||||
.filter(Func::isNotBlank)
|
||||
.map(String::trim)
|
||||
.distinct()
|
||||
.toList();
|
||||
}
|
||||
|
||||
/** 结算明细(上下文缓存优先):批量预检加载过的明细推送时直接复用,消除逐单重复查询 */
|
||||
private List<FormalSettlementDetail> settlementDetails(PaymentApplication entity, KingdeeSyncContext context) {
|
||||
return context.settlementDetailCache().computeIfAbsent(entity.getId(), key -> formalSettlementDetails(entity));
|
||||
}
|
||||
|
||||
/** 财务应付单防重键来源单据号:付款申请号 + 结算明细单据号下划线拼接(与 A102-2 保存传参一致) */
|
||||
private String apBillSrcCode(PaymentApplication entity, KingdeeSyncContext context) {
|
||||
return ExternalSrcCodeSupport.buildSrcCode(entity.getPaymentNo(), settlementDocumentNos(settlementDetails(entity, context)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量同步前 A102-4 预检:一次批量查询整批付款申请的财务应付单是否已生成,
|
||||
* 结果(含"未生成"标记)写入上下文缓存,供逐单推送时复用,消除逐单远程查询(N+1)。
|
||||
* 仅预检会真正走到推送的正式结算单据(审批通过且未生成/生成失败),已生成/付款中等状态在
|
||||
* doSyncKingdee 入口即返回,无需预检
|
||||
*
|
||||
* @param ids 待同步付款申请id批次
|
||||
* @param context 金蝶同步上下文(缓存载体)
|
||||
*/
|
||||
private void preloadApBillExistNos(List<Long> ids, KingdeeSyncContext context) {
|
||||
List<PaymentApplication> applications = list(Wrappers.<PaymentApplication>lambdaQuery()
|
||||
.in(PaymentApplication::getId, ids)
|
||||
.eq(PaymentApplication::getApprovalStatus, APPROVED)
|
||||
.notIn(PaymentApplication::getKingdeeStatus, KingdeeBfiConstant.KINGDEE_STATUS_SYNCED,
|
||||
KingdeeBfiConstant.KINGDEE_STATUS_PAYING, KingdeeBfiConstant.KINGDEE_STATUS_PAID, KingdeeBfiConstant.KINGDEE_STATUS_CLOSED));
|
||||
List<String> srcCodes = new ArrayList<>();
|
||||
for (PaymentApplication entity : applications) {
|
||||
// 仅正式结算付款走财务应付单链路,预付款跳过
|
||||
if (!TransportBusiConstant.PAYMENT_TYPE_SETTLEMENT.equals(entity.getPaymentType())) {
|
||||
continue;
|
||||
}
|
||||
srcCodes.add(apBillSrcCode(entity, context));
|
||||
}
|
||||
// 仅查询缓存未命中的编码,已命中的(同批重复/已预热)直接复用
|
||||
List<String> pendingCodes = srcCodes.stream()
|
||||
.filter(Func::isNotBlank)
|
||||
.filter(code -> !context.apBillNoCache().containsKey(code))
|
||||
.distinct()
|
||||
.toList();
|
||||
if (pendingCodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
context.apBillNoCache().putAll(queryApBillExistNos(pendingCodes));
|
||||
// 未命中编码补"未生成"标记(空串),避免逐单推送时重复远程查询
|
||||
pendingCodes.forEach(code -> context.apBillNoCache().putIfAbsent(code, ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* 单条来源行(货物费用行或结算明细行)按货物类型并入分录组;一行含多种类型时金额与数量按份数均分(尾差计入最后一份)
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user