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