From aa063797377063cf08e11d7813b37dacbaf8e832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com> Date: Thu, 24 Sep 2026 19:42:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BB=98=E6=AC=BE=E7=94=B3=E8=AF=B7?= =?UTF-8?q?=E9=87=91=E8=9D=B6=E6=8E=A8=E9=80=81=E5=AE=8C=E5=96=84=E5=BE=80?= =?UTF-8?q?=E6=9D=A5=E8=B4=A6=E6=88=B7=EF=BC=88=E5=AE=A2=E5=95=86=E6=94=B6?= =?UTF-8?q?=E6=AC=BE=E8=B4=A6=E6=88=B7=E8=81=94=E8=A1=8C=E5=8F=B7=EF=BC=89?= =?UTF-8?q?=E4=B8=8E=E7=BB=93=E7=AE=97=E6=96=B9=E5=BC=8F=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/PaymentApplicationServiceImpl.java | 161 ++++++++++++------ 1 file changed, 113 insertions(+), 48 deletions(-) diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java index cdb00917..38ea696e 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/PaymentApplicationServiceImpl.java @@ -53,6 +53,7 @@ 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.CustomerReceiptAccountMapper; import org.springblade.transport.mapper.FormalSettlementDetailMapper; import org.springblade.transport.mapper.FormalSettlementMapper; import org.springblade.transport.mapper.FormalSettlementPaymentMapper; @@ -73,6 +74,7 @@ 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.CustomerReceiptAccount; import org.springblade.transport.pojo.entity.FormalSettlement; import org.springblade.transport.pojo.entity.FormalSettlementDetail; import org.springblade.transport.pojo.entity.FormalSettlementPayment; @@ -134,6 +136,7 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl entryGroups = - kingdeeApBillSyncSupport.resolveEntryGroups(settlementDetails(entity, context), context); - log.info("付款申请[{}]正式结算付款:金蝶财务应付单(A102-2)已生成,开始推送金蝶付款申请单(A103-1 应付下推),分录{}条", - entity.getPaymentNo(), entryGroups.size()); - kingdeeBillId = pushBfiPayApplyPush(entity, entryGroups, context); + log.info("付款申请[{}]正式结算付款:金蝶财务应付单(A102-2)已生成,开始推送金蝶付款申请单(A103-1 应付下推)", + entity.getPaymentNo()); + kingdeeBillId = pushBfiPayApplyPush(entity, context); log.info("付款申请[{}]金蝶付款申请单(A103-1 应付下推)推送成功:kingdeeBillId={}", entity.getPaymentNo(), kingdeeBillId); } } else { @@ -917,17 +916,16 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl entryGroups, KingdeeSyncContext context) { + private String pushBfiPayApplyPush(PaymentApplication entity, KingdeeSyncContext context) { ContractManage contract = kingdeeApBillSyncSupport.requireContract(entity.getContractId(), context); String orgNumber = kingdeeApBillSyncSupport.bfiOrgNumber(contract); // 申请日期:yyyy-MM-dd HH:mm:ss(与 A102-2 单据日期格式统一) @@ -954,46 +952,113 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl entries = new ArrayList<>(); - // 结算方式.编码:按本单付款方式映射(汇票付款→金蝶应付票据电子银行承兑汇票 012-02,其余→银行转账 02),仅 A103-1 下推需要 - String settlementtypeNumber = isBillPayment(entity.getPaymentMethod()) - ? BfiConstant.SETTLE_TYPE_PAYABLE_BANK_ELECTRONIC : BfiConstant.SETTLE_TYPE_BANK; - for (KingdeeApBillSyncSupport.BfiEntryGroup entryGroup : entryGroups) { - // 【必填】结算单分录id勾稽值(awrp_finapbill_entryid):A102-2 保存未传 planentity,金蝶自动生成的付款计划分录 - // awrp_entry_code_p 即外部系统单据号(应付单防重键:正式结算单号_结算明细单据号拼接,本地按数据库数据组装,不远程反查) - String finapbillEntryid = settlementApBillSrcCode(entity, entryGroup.formalSettlementId(), context); - BfiPayApplyPushEntryDTO entry = new BfiPayApplyPushEntryDTO(); - // 【必填】付款类型.编码:正式付款固定 201 - entry.setEPaymenttypeNumber(KingdeeBfiConstant.BFI_PAYMENT_TYPE_FORMAL); - // 结算方式.编码:不传时金蝶按应付单自动带出,此处按付款方式映射显式送值 - entry.setESettlementtypeNumber(settlementtypeNumber); - // 【必填】结算单分录id:A102-2 财务应付单付款计划分录的外部系统来源分录标识(awrp_entry_code_p) - entry.setAwrpFinapbillEntryid(finapbillEntryid); - // 【必填】对方系统唯一行id(不能重复):费用明细行id(与应付单的勾稽走 awrp_finapbill_entryid,与本标识无关) - entry.setAwrpEntryCode(entryGroup.entryCode()); - // 【必填】往来账户:乙方(收款方)银行账号 - entry.setEAssacct(entity.getBankAccount()); - // 【必填】往来银行.编码(联调期临时传金蝶测试档案值,待建立银行档案编码映射后调整)todo - entry.setEBebankNumber(KingdeeBfiConstant.BFI_AP_BILL_BANKACCOUNT_NUMBER_TEST); - // 【必填】申请金额:与对应应付单分录结算金额(含税)保持一致 - entry.setEApplyamount(entryGroup.amount()); - // 【必填】项目.项目编码(联调期临时传金蝶测试档案值) - entry.setProjectNumber(KingdeeBfiConstant.BFI_AP_BILL_PROJECT_NUMBER_TEST); - // 期望付款日(非必传,不传时根据应付单自动带出) - // entry.setEExpaydate(applyDateText); - // 备注(非必传) - // entry.setERemark(entity.getRemark()); - // 【必填】外部单据类型 todo - entry.setAwrpSrcType(bfiProperties.getPayApply().getSrcType()); - entries.add(entry); - } - param.setEntry(entries); + // 付款申请分录与财务应付单付款计划分录勾稽(awrp_finapbill_entryid 关联应付单 awrp_entry_code_p,A102-4 反查) + BfiPayApplyPushEntryDTO entry = new BfiPayApplyPushEntryDTO(); + // 【必填】付款类型.编码:正式付款固定 201 + entry.setEPaymenttypeNumber(KingdeeBfiConstant.BFI_PAYMENT_TYPE_FORMAL); + // 结算方式.编码:不传时金蝶按应付单自动带出,此处按付款方式映射显式送值(汇票付款→金蝶应付票据电子银行承兑汇票 012-02,其余→银行转账 02) + entry.setESettlementtypeNumber(isBillPayment(entity.getPaymentMethod()) + ? BfiConstant.SETTLE_TYPE_PAYABLE_BANK_ELECTRONIC : BfiConstant.SETTLE_TYPE_BANK); + // 【必填】结算单分录id:A102-2 财务应付单付款计划分录的外部系统来源分录标识(awrp_entry_code_p),按付款申请主结算单防重键勾稽 + entry.setAwrpFinapbillEntryid(settlementApBillSrcCode(entity, requireMainSettlementId(entity), context)); + // 【必填】对方系统唯一行id(不能重复):付款申请号-1 + entry.setAwrpEntryCode(bfiEntryCode(entity.getPaymentNo(), 1)); + // 【必填】往来账户:乙方(收款方)银行账号 + entry.setEAssacct(entity.getBankAccount()); + // 【必填】往来银行.编码:取客商收款信息(blade_customer_receipt_account)联行号 + entry.setEBebankNumber(bfiBebankNumber(entity, context)); + // 【必填】申请金额:取付款申请填写的申请付款金额 + entry.setEApplyamount(money(entity.getAppliedAmount()).setScale(2, RoundingMode.HALF_UP)); + // 【必填】项目.项目编码(联调期临时传金蝶测试档案值) + entry.setProjectNumber(KingdeeBfiConstant.BFI_AP_BILL_PROJECT_NUMBER_TEST); + // 期望付款日(非必传,不传时根据应付单自动带出) + // entry.setEExpaydate(applyDateText); + // 备注(非必传) + // entry.setERemark(entity.getRemark()); + // 【必填】外部单据类型 todo + entry.setAwrpSrcType(bfiProperties.getPayApply().getSrcType()); + param.setEntry(List.of(entry)); BfiBillSaveResultVO saveResult = bfiService.pushPayApply(param); return requireBfiBillIdAndFillNo(entity, saveResult, "推送金蝶付款申请(应付下推)"); } + /** + * 付款申请勾稽的主结算单id:付款申请仅推一条分录,按主结算单的财务应付单防重键勾稽。 + * 优先取付款申请记录的主结算单id;聚合多结算单场景主结算单id为空时,取关联结算明细中首个结算单id。 + * + * @param entity 付款申请实体 + * @return 主结算单id + */ + private Long requireMainSettlementId(PaymentApplication entity) { + if (entity.getSettlementId() != null) { + return entity.getSettlementId(); + } + Long settlementId = formalSettlementDetails(entity).stream() + .map(FormalSettlementDetail::getFormalSettlementId) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); + if (settlementId == null) { + throw new ServiceException("推送金蝶付款申请失败:付款申请[" + entity.getPaymentNo() + "]未关联正式结算单,无法勾稽财务应付单"); + } + return settlementId; + } + + /** + * 往来银行编码(金蝶 e_bebank_number):取付款申请所选客商收款信息(blade_customer_receipt_account)的联行号。 + * 优先按收款账户id直查,批量同步时经上下文缓存复用; + * 收款账户id缺失时,按合同乙方客商 + 收款账号兜底匹配(默认账户优先)。 + * + * @param entity 付款申请实体 + * @param context 金蝶同步上下文(缓存载体) + * @return 联行号 + */ + private String bfiBebankNumber(PaymentApplication entity, KingdeeSyncContext context) { + CustomerReceiptAccount receiptAccount = receiptAccount(entity, context); + if (receiptAccount == null || Func.isBlank(receiptAccount.getCnapsCode())) { + throw new ServiceException("推送金蝶付款申请失败:付款申请[" + entity.getPaymentNo() + + "]收款账户未维护联行号,请先在客商档案维护收款信息联行号"); + } + return receiptAccount.getCnapsCode().trim(); + } + + /** 付款申请对应的客商收款信息(上下文缓存优先),收款账户id缺失时按合同乙方客商 + 收款账号兜底匹配 */ + private CustomerReceiptAccount receiptAccount(PaymentApplication entity, KingdeeSyncContext context) { + if (entity.getReceiptAccountId() != null) { + return context.receiptAccountCache().computeIfAbsent(entity.getReceiptAccountId(), receiptAccountId -> { + CustomerReceiptAccount receiptAccount = receiptAccountMapper.selectById(receiptAccountId); + if (receiptAccount == null || Objects.equals(receiptAccount.getIsDeleted(), 1)) { + throw new ServiceException("推送金蝶付款申请失败:付款申请[" + entity.getPaymentNo() + + "]收款账户[" + receiptAccountId + "]不存在或已删除"); + } + return receiptAccount; + }); + } + ContractManage contract = kingdeeApBillSyncSupport.requireContract(entity.getContractId(), context); + if (Func.isBlank(contract.getPartyB())) { + return null; + } + CustomerArchive customer = customerArchiveMapper.selectOne(Wrappers.lambdaQuery() + .and(wrapper -> wrapper.eq(CustomerArchive::getFullName, contract.getPartyB()) + .or().eq(CustomerArchive::getShortName, contract.getPartyB())) + .eq(CustomerArchive::getIsDeleted, 0).last("limit 1")); + if (customer == null) { + return null; + } + List receiptAccounts = receiptAccountMapper.selectList(Wrappers.lambdaQuery() + .eq(CustomerReceiptAccount::getCustomerId, customer.getId()) + .eq(Func.isNotBlank(entity.getBankAccount()), CustomerReceiptAccount::getBankAccount, entity.getBankAccount()) + .eq(CustomerReceiptAccount::getIsDeleted, 0) + .orderByDesc(CustomerReceiptAccount::getIsDefault) + .orderByAsc(CustomerReceiptAccount::getCreateTime)); + CustomerReceiptAccount receiptAccount = receiptAccounts.isEmpty() ? null : receiptAccounts.get(0); + if (receiptAccount != null && receiptAccount.getId() != null) { + context.receiptAccountCache().putIfAbsent(receiptAccount.getId(), receiptAccount); + } + return receiptAccount; + } + /** * 校验金蝶保存/下推返回结果,取星瀚单据id并即时回填付款申请单编号(kingdeeBillNo): * 推送结果携带金蝶单据编号(number),同步完成列表立即可见,无需等待 A103-2 定时回写; @@ -1060,7 +1125,7 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl