fix: 修复收款流水同步与认领推送问题

This commit is contained in:
刘泉佳
2026-09-28 17:54:43 +08:00
parent 0b88d05e93
commit 145cb57e00
3 changed files with 99 additions and 15 deletions
@@ -140,6 +140,9 @@ public final class KingdeeBfiConstant {
/** A303-1 上游来源单据类型:财务应收单(awrp_src_bt)。 */ /** A303-1 上游来源单据类型:财务应收单(awrp_src_bt)。 */
public static final String BFI_AR_BILL_SRC_BT = "ar_finarbill"; public static final String BFI_AR_BILL_SRC_BT = "ar_finarbill";
/** A301-3 认领推送核心单据类型:其他应付(e_corebilltype)。 */
public static final String BFI_CLAIM_CORE_BILL_TYPE = "ApFin_other_BT_S";
/** A303-1 发票种类:数电发票(普通发票)。 */ /** A303-1 发票种类:数电发票(普通发票)。 */
public static final String BFI_INVOICE_TYPE_DIGITAL_GENERAL = "10xdp"; public static final String BFI_INVOICE_TYPE_DIGITAL_GENERAL = "10xdp";
@@ -207,10 +210,10 @@ public final class KingdeeBfiConstant {
public static final String POOL_INVOICE_STATUS_NORMAL = "0"; public static final String POOL_INVOICE_STATUS_NORMAL = "0";
/** A301-3 认领推送:收款类型.编码(示例 101,待金蝶确认后如有调整直接改此常量)。 */ /** A301-3 认领推送:收款类型.编码(示例 101,待金蝶确认后如有调整直接改此常量)。 */
public static final String BFI_CLAIM_REC_PAY_TYPE = "101"; public static final String BFI_CLAIM_REC_PAY_TYPE = "999";
/** A301-3 认领推送:付款人类型(默认客户 bd_customer,待金蝶确认后如有调整直接改此常量)。 */ /** A301-3 认领推送:付款人类型(默认客户 bd_customer,待金蝶确认后如有调整直接改此常量)。 */
public static final String BFI_CLAIM_PAYMENT_TYPE = BFI_CUSTOMER_ASSTACT_TYPE; public static final String BFI_CLAIM_PAYMENT_TYPE = "999";
/** A301-3 认领推送来源单据编码前缀:SKCL + yyyyMMddHHmmss + 认领id尾号,作 A301-1 回写匹配键。 */ /** A301-3 认领推送来源单据编码前缀:SKCL + yyyyMMddHHmmss + 认领id尾号,作 A301-1 回写匹配键。 */
public static final String BFI_CLAIM_SRC_CODE_PREFIX = "SKCL"; public static final String BFI_CLAIM_SRC_CODE_PREFIX = "SKCL";
@@ -90,10 +90,15 @@ import java.util.stream.Collectors;
public class ReceiptFlowServiceImpl extends BaseServiceImpl<KingdeeReceiptFlowMapper, KingdeeReceiptFlow> public class ReceiptFlowServiceImpl extends BaseServiceImpl<KingdeeReceiptFlowMapper, KingdeeReceiptFlow>
implements IReceiptFlowService { implements IReceiptFlowService {
// 未认领
private static final String UNCLAIMED = "unclaimed"; private static final String UNCLAIMED = "unclaimed";
// 部分认领
private static final String PARTIAL = "partial"; private static final String PARTIAL = "partial";
// 已认领
private static final String CLAIMED = "claimed"; private static final String CLAIMED = "claimed";
// 已审批
private static final String APPROVED = "approved"; private static final String APPROVED = "approved";
// 应收款
private static final String RECEIVABLE = "receivable"; private static final String RECEIVABLE = "receivable";
/** /**
* A301-2 认领公告同步分页大小 * A301-2 认领公告同步分页大小
@@ -233,18 +238,28 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl<KingdeeReceiptFlowMa
} }
validateLength(request.getRemark(), 200, "备注不能超过200字"); validateLength(request.getRemark(), 200, "备注不能超过200字");
// 收款流水
KingdeeReceiptFlow flow = lockedFlow(request.getFlowId()); KingdeeReceiptFlow flow = lockedFlow(request.getFlowId());
// 结算单id → 分摊金额
Map<Long, BigDecimal> allocationMap = allocationMap(request.getSettlements()); Map<Long, BigDecimal> allocationMap = allocationMap(request.getSettlements());
// 结算单id列表(升序)
List<Long> settlementIds = allocationMap.keySet().stream().sorted().toList(); List<Long> settlementIds = allocationMap.keySet().stream().sorted().toList();
// 结算单id → 结算单实体
Map<Long, FormalSettlement> settlementMap = lockSettlements(settlementIds); Map<Long, FormalSettlement> settlementMap = lockSettlements(settlementIds);
// 分摊的结算单列表
List<FormalSettlement> settlements = settlementIds.stream().map(settlementMap::get).toList(); List<FormalSettlement> settlements = settlementIds.stream().map(settlementMap::get).toList();
assertCompatible(settlements); assertCompatible(settlements);
// 结算单id → 认领前已认领金额
Map<Long, BigDecimal> previousClaimedMap = new LinkedHashMap<>(); Map<Long, BigDecimal> previousClaimedMap = new LinkedHashMap<>();
// 本次分摊总金额
BigDecimal allocatedTotal = BigDecimal.ZERO; BigDecimal allocatedTotal = BigDecimal.ZERO;
for (FormalSettlement settlement : settlements) { for (FormalSettlement settlement : settlements) {
// 本次分摊金额
BigDecimal allocated = allocationMap.get(settlement.getId()); BigDecimal allocated = allocationMap.get(settlement.getId());
// 认领前已认领金额
BigDecimal previousClaimed = settlementClaimedAmount(settlement.getId()); BigDecimal previousClaimed = settlementClaimedAmount(settlement.getId());
// 结算总金额
BigDecimal settlementAmount = positiveMoney(settlement.getSettlementAmount(), "结算总金额"); BigDecimal settlementAmount = positiveMoney(settlement.getSettlementAmount(), "结算总金额");
if (previousClaimed.add(allocated).compareTo(settlementAmount) > 0) { if (previousClaimed.add(allocated).compareTo(settlementAmount) > 0) {
throw new ServiceException("结算单" + settlement.getFormalSettlementNo() throw new ServiceException("结算单" + settlement.getFormalSettlementNo()
@@ -254,51 +269,84 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl<KingdeeReceiptFlowMa
allocatedTotal = allocatedTotal.add(allocated); allocatedTotal = allocatedTotal.add(allocated);
} }
// 收款金额
BigDecimal receiptAmount = positiveMoney(flow.getReceiptAmount(), "收款金额"); BigDecimal receiptAmount = positiveMoney(flow.getReceiptAmount(), "收款金额");
// 流水认领前已认领金额
BigDecimal previousFlowClaimed = flowClaimedAmount(flow.getId()); BigDecimal previousFlowClaimed = flowClaimedAmount(flow.getId());
if (previousFlowClaimed.add(allocatedTotal).compareTo(receiptAmount) > 0) { if (previousFlowClaimed.add(allocatedTotal).compareTo(receiptAmount) > 0) {
throw new ServiceException("本次分摊金额不能超过流水剩余可认领金额"); throw new ServiceException("本次分摊金额不能超过流水剩余可认领金额");
} }
// 当前用户部门
Dept dept = TransportBusinessSupport.currentDept("收款流水认领"); Dept dept = TransportBusinessSupport.currentDept("收款流水认领");
// 认领主单
ReceiptClaim claim = new ReceiptClaim(); ReceiptClaim claim = new ReceiptClaim();
// 收款流水id
claim.setReceiptFlowId(flow.getId()); claim.setReceiptFlowId(flow.getId());
// 认领金额
claim.setClaimAmount(allocatedTotal); claim.setClaimAmount(allocatedTotal);
// 认领人id
claim.setClaimerId(AuthUtil.getUserId()); claim.setClaimerId(AuthUtil.getUserId());
// 认领人姓名
claim.setClaimerName(UserCache.getUserRealName(AuthUtil.getUserId())); claim.setClaimerName(UserCache.getUserRealName(AuthUtil.getUserId()));
// 认领人部门id
claim.setClaimerDeptId(dept.getId()); claim.setClaimerDeptId(dept.getId());
// 认领人部门名称
claim.setClaimerDeptName(dept.getDeptName()); claim.setClaimerDeptName(dept.getDeptName());
// 认领日期
claim.setClaimDate(LocalDate.now()); claim.setClaimDate(LocalDate.now());
// 附件json
claim.setAttachmentsJson(request.getAttachmentsJson()); claim.setAttachmentsJson(request.getAttachmentsJson());
// 备注
claim.setRemark(trimToNull(request.getRemark())); claim.setRemark(trimToNull(request.getRemark()));
// 认领状态
claim.setClaimStatus(CLAIMED); claim.setClaimStatus(CLAIMED);
// 金蝶单据状态(待推送)
claim.setKingdeeBillStatus("none"); claim.setKingdeeBillStatus("none");
claimMapper.insert(claim); claimMapper.insert(claim);
for (FormalSettlement settlement : settlements) { for (FormalSettlement settlement : settlements) {
// 认领前已认领金额
BigDecimal previousClaimed = previousClaimedMap.get(settlement.getId()); BigDecimal previousClaimed = previousClaimedMap.get(settlement.getId());
// 本次分摊金额
BigDecimal allocated = allocationMap.get(settlement.getId()); BigDecimal allocated = allocationMap.get(settlement.getId());
// 认领后累计金额
BigDecimal claimedAfter = previousClaimed.add(allocated); BigDecimal claimedAfter = previousClaimed.add(allocated);
// 认领结算单分摊关系
ReceiptClaimSettlement relation = new ReceiptClaimSettlement(); ReceiptClaimSettlement relation = new ReceiptClaimSettlement();
// 认领主单id
relation.setReceiptClaimId(claim.getId()); relation.setReceiptClaimId(claim.getId());
// 收款流水id
relation.setReceiptFlowId(flow.getId()); relation.setReceiptFlowId(flow.getId());
// 结算单id
relation.setFormalSettlementId(settlement.getId()); relation.setFormalSettlementId(settlement.getId());
// 结算单号
relation.setFormalSettlementNo(settlement.getFormalSettlementNo()); relation.setFormalSettlementNo(settlement.getFormalSettlementNo());
// 结算总金额
relation.setSettlementAmount(money(settlement.getSettlementAmount())); relation.setSettlementAmount(money(settlement.getSettlementAmount()));
// 认领前已认领金额
relation.setClaimedReceiptAmount(previousClaimed); relation.setClaimedReceiptAmount(previousClaimed);
// 本次分摊金额
relation.setAllocatedReceiptAmount(allocated); relation.setAllocatedReceiptAmount(allocated);
claimSettlementMapper.insert(relation); claimSettlementMapper.insert(relation);
// 刷新结算单收款汇总
formalSettlementService.refreshPaymentSummary(settlement.getId()); formalSettlementService.refreshPaymentSummary(settlement.getId());
} }
// 认领前状态
String fromStatus = normalizeClaimStatus(flow.getClaimStatus()); String fromStatus = normalizeClaimStatus(flow.getClaimStatus());
// 认领后累计金额
BigDecimal claimedAfter = previousFlowClaimed.add(allocatedTotal); BigDecimal claimedAfter = previousFlowClaimed.add(allocatedTotal);
// 认领后状态
String toStatus = amountClaimStatus(claimedAfter, receiptAmount); String toStatus = amountClaimStatus(claimedAfter, receiptAmount);
// 更新流水已认领金额
flow.setClaimedAmount(claimedAfter); flow.setClaimedAmount(claimedAfter);
// 更新流水认领状态
flow.setClaimStatus(toStatus); flow.setClaimStatus(toStatus);
updateById(flow); updateById(flow);
// 记录操作日志
record(flow.getId(), claim.getId(), "claim", "认领收款流水", fromStatus, toStatus, record(flow.getId(), claim.getId(), "claim", "认领收款流水", fromStatus, toStatus,
allocatedTotal, "关联" + settlements.size() + "张应收正式结算单"); allocatedTotal, "关联" + settlements.size() + "张应收正式结算单");
@@ -315,10 +363,10 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl<KingdeeReceiptFlowMa
} }
// 从配置读取查询时间窗口(月数),默认近半年 // 从配置读取查询时间窗口(月数),默认近半年
int months = bfiProperties.getClaimAnnounce().getMonths(); int months = bfiProperties.getClaimAnnounce().getMonths();
LocalDate endDate = LocalDate.now(); LocalDateTime endDate = LocalDateTime.now();
LocalDate startDate = endDate.minusMonths(months); LocalDateTime startDate = endDate.minusMonths(months);
String modifytimeS = startDate.format(DateTimeFormatter.ISO_LOCAL_DATE); String modifytimeS = startDate.format(BFI_DATE_TIME_FORMATTER);
String modifytimeE = endDate.format(DateTimeFormatter.ISO_LOCAL_DATE); String modifytimeE = endDate.format(BFI_DATE_TIME_FORMATTER);
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
log.info("调用BFI接口 收款认领公告查询开始 claimusers:{},时间窗口:{} ~ {}(近{}个月)", log.info("调用BFI接口 收款认领公告查询开始 claimusers:{},时间窗口:{} ~ {}(近{}个月)",
@@ -593,28 +641,39 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl<KingdeeReceiptFlowMa
claim.setAwrpSrcCode(awrpSrcCode); claim.setAwrpSrcCode(awrpSrcCode);
BfiClaimPushDTO param = new BfiClaimPushDTO(); BfiClaimPushDTO param = new BfiClaimPushDTO();
// 【必填】认领公告id
param.setBillid(flow.getBillId()); param.setBillid(flow.getBillId());
// 【必填】来源系统编码
param.setAwrpSrcSys(bfiProperties.getSrcSys()); param.setAwrpSrcSys(bfiProperties.getSrcSys());
// 【必填】来源系统单据编码
param.setAwrpSrcCode(awrpSrcCode); param.setAwrpSrcCode(awrpSrcCode);
// 【必填】收款类型.编码
param.setRecpaytypeNumber(KingdeeBfiConstant.BFI_CLAIM_REC_PAY_TYPE); param.setRecpaytypeNumber(KingdeeBfiConstant.BFI_CLAIM_REC_PAY_TYPE);
// 【必填】付款人类型
param.setPaymenttype(KingdeeBfiConstant.BFI_CLAIM_PAYMENT_TYPE); param.setPaymenttype(KingdeeBfiConstant.BFI_CLAIM_PAYMENT_TYPE);
// 【必填】付款人名称
param.setRecviewpayer(flow.getPayerName()); param.setRecviewpayer(flow.getPayerName());
// 【必填】付款人id
param.setRecpayer(flow.getPayerId()); param.setRecpayer(flow.getPayerId());
List<BfiClaimPushEntryDTO> entries = new ArrayList<>(); List<BfiClaimPushEntryDTO> entries = new ArrayList<>();
int seq = 1;
BigDecimal allocatedTotal = BigDecimal.ZERO; BigDecimal allocatedTotal = BigDecimal.ZERO;
for (FormalSettlement settlement : settlements) { for (FormalSettlement settlement : settlements) {
BfiClaimPushEntryDTO entry = new BfiClaimPushEntryDTO(); BfiClaimPushEntryDTO entry = new BfiClaimPushEntryDTO();
// 【必填】应收金额
entry.setEReceivableamt(allocationMap.get(settlement.getId())); entry.setEReceivableamt(allocationMap.get(settlement.getId()));
entry.setSeq(seq++); // 结算单id
entry.setSeq(settlement.getId());
if (Func.isNotEmpty(settlement.getKingdeeBillNo())) { if (Func.isNotEmpty(settlement.getKingdeeBillNo())) {
// 结算单已同步金蝶应收单时携带核心单据引用,金蝶按应收单号核销认领金额 // 结算单已同步金蝶应收单时携带核心单据引用,金蝶按应收单号核销认领金额
entry.setECorebilltype(KingdeeBfiConstant.BFI_AR_BILL_SRC_BT); // 核心单据类型
entry.setECorebilltype(KingdeeBfiConstant.BFI_CLAIM_CORE_BILL_TYPE);
// 核心单据编号
entry.setECorebillno(settlement.getKingdeeBillNo()); entry.setECorebillno(settlement.getKingdeeBillNo());
} }
allocatedTotal = allocatedTotal.add(money(allocationMap.get(settlement.getId()))); allocatedTotal = allocatedTotal.add(money(allocationMap.get(settlement.getId())));
entries.add(entry); entries.add(entry);
} }
// 【必填】单据体分录
param.setEntryentity(entries); param.setEntryentity(entries);
log.info("调用BFI接口 收款认领结果推送开始 claimId:{},billId:{},awrpSrcCode:{},分摊结算单 {} 张,分摊金额 {}", log.info("调用BFI接口 收款认领结果推送开始 claimId:{},billId:{},awrpSrcCode:{},分摊结算单 {} 张,分摊金额 {}",
@@ -671,21 +730,39 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl<KingdeeReceiptFlowMa
*/ */
private void copyAnnounceRow(KingdeeReceiptFlow target, BfiClaimAnnounceVO source, private void copyAnnounceRow(KingdeeReceiptFlow target, BfiClaimAnnounceVO source,
String detailSerialNo, BigDecimal receiptAmount) { String detailSerialNo, BigDecimal receiptAmount) {
// 金蝶认领公告id
target.setBillId(source.getId()); target.setBillId(source.getId());
target.setReceiptNoticeNo(trimToNull(source.getBillno())); // 收款通知单号
target.setPayerName(trimToNull(source.getRecviewpayer())); target.setReceiptNoticeNo(trimToEmpty(source.getBillno()));
// 付款人名称
target.setPayerName(trimToEmpty(source.getRecviewpayer()));
// 付款人id
target.setPayerId(trimToEmpty(source.getRecpayer()));
// 收款人
target.setPayeeName(trimToNull(source.getRecpayee())); target.setPayeeName(trimToNull(source.getRecpayee()));
// 收款金额
target.setReceiptAmount(receiptAmount); target.setReceiptAmount(receiptAmount);
target.setCounterpartyName(trimToNull(source.getOppunit())); // 对方单位名称
target.setCounterpartyAccount(trimToNull(source.getOppbanknumber())); target.setCounterpartyName(trimToEmpty(source.getOppunit()));
target.setCounterpartyBank(trimToNull(source.getOppbank())); // 对方银行账号
target.setCounterpartyAccount(trimToEmpty(source.getOppbanknumber()));
// 对方开户行
target.setCounterpartyBank(trimToEmpty(source.getOppbank()));
// 摘要
target.setSummary(trimToNull(source.getDescription())); target.setSummary(trimToNull(source.getDescription()));
// 交易日期
target.setTransactionTime(parseDateTime(source.getTradetime())); target.setTransactionTime(parseDateTime(source.getTradetime()));
// 明细流水号
target.setDetailSerialNo(detailSerialNo); target.setDetailSerialNo(detailSerialNo);
// 未认领金额
target.setUnclaimedAmount(money(source.getUnclaimamount())); target.setUnclaimedAmount(money(source.getUnclaimamount()));
// 手续费
target.setFee(source.getFee() == null ? null : source.getFee().setScale(2, RoundingMode.HALF_UP)); target.setFee(source.getFee() == null ? null : source.getFee().setScale(2, RoundingMode.HALF_UP));
// 公告认领状态
target.setKingdeeClaimStatus(trimToNull(source.getClaimstatus())); target.setKingdeeClaimStatus(trimToNull(source.getClaimstatus()));
// 我已认领
target.setClaimMe(source.getClaimme()); target.setClaimMe(source.getClaimme());
// 来源更新时间
target.setSourceUpdatedTime(target.getTransactionTime() == null target.setSourceUpdatedTime(target.getTransactionTime() == null
? LocalDateTime.now() : target.getTransactionTime()); ? LocalDateTime.now() : target.getTransactionTime());
} }
@@ -748,6 +825,10 @@ public class ReceiptFlowServiceImpl extends BaseServiceImpl<KingdeeReceiptFlowMa
return value == null || value.trim().isEmpty() ? null : value.trim(); return value == null || value.trim().isEmpty() ? null : value.trim();
} }
private String trimToEmpty(String value) {
return value == null || value.trim().isEmpty() ? "" : value.trim();
}
private void validateLength(String value, int maxLength, String message) { private void validateLength(String value, int maxLength, String message) {
if (value != null && value.length() > maxLength) { if (value != null && value.length() > maxLength) {
throw new ServiceException(message); throw new ServiceException(message);
@@ -61,7 +61,7 @@ public class BfiClaimPushEntryDTO implements Serializable {
/** /**
* 分录行号 * 分录行号
*/ */
private Integer seq; private Long seq;
/** /**
* 收款类型.编码 * 收款类型.编码
*/ */